<?php

namespace app\common\command;


use app\common\service\SseParser;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Cache;
use think\facade\Log;

/**
 * 医案文本处理器 - 优化版本
 * 采用单行文件处理方式，使用Redis管理任务队列，支持并发处理
 * 
 * @package app\common\command
 */
class MedicalCaseProcessor extends Command {
    /**
     * Redis缓存键前缀
     */
    const CACHE_PREFIX = 'medical_case:';

    /**
     * 缓存过期时间（秒）
     */
    const CACHE_EXPIRE = 604800; // 1周

    /**
     * 医案文件路径
     */
    const MEDICAL_CASE_FILE = 'public/uploads/sftdoc/medical_case.json';

    /**
     * 输出文件路径
     */
    const OUTPUT_FILE = 'public/uploads/sftdoc/medical_case_new.json';

    /**
     * 并发处理数量
     */
    const CONCURRENT_LIMIT = 25;

    /**
     * 任务状态
     */
    const STATUS_PENDING = 'pending';    // 待处理
    const STATUS_PROCESSING = 'processing'; // 处理中
    const STATUS_COMPLETED = 'completed';   // 已完成
    const STATUS_FAILED = 'failed';      // 失败

    /**
     * 企业微信机器人Webhook地址（如不需要通知可留空）
     */
    const WECHAT_WEBHOOK_URL = '';

    /**
     * AI服务配置
     */
    const AI_BASE_URL = 'https://ai.gitee.com/v1/chat/completions';
    const AI_API_KEY = ''; // 请填入您的AI API密钥

    protected function configure() {
        $this->setName('medicalCase')
            ->setDescription('处理医案文本数据，采用单行文件处理方式，支持并发处理')
            ->addOption('model', 'm', \think\console\input\Option::VALUE_OPTIONAL, '指定AI模型', 'Qwen2.5-72B-Instruct')
            ->addOption('concurrent', 'c', \think\console\input\Option::VALUE_OPTIONAL, '并发处理数量', self::CONCURRENT_LIMIT)
            ->addOption('clear-cache', null, \think\console\input\Option::VALUE_NONE, '清理缓存')
            ->addOption('reset-progress', null, \think\console\input\Option::VALUE_NONE, '重置处理进度')
            ->addOption('status', 's', \think\console\input\Option::VALUE_NONE, '查看处理状态')
            ->addOption('restart-task', 'r', \think\console\input\Option::VALUE_REQUIRED, '重启指定任务ID')
            ->addOption('restart-failed', null, \think\console\input\Option::VALUE_NONE, '重启所有失败的任务')
            ->addOption('restart-range', null, \think\console\input\Option::VALUE_REQUIRED, '重启指定范围的任务，格式：start-end')
            ->addOption('clear-before', null, \think\console\input\Option::VALUE_REQUIRED, '删除指定ID之前的所有任务缓存')
            ->addOption('sync-cache', null, \think\console\input\Option::VALUE_NONE, '同步cached_task_ids与实际缓存')
            ->addOption('flush-cache', null, \think\console\input\Option::VALUE_NONE, '强制写入所有暂存器数据到文件');
    }

    protected function execute(Input $input, Output $output) {
        // 检查是否为同步缓存操作
        if ($input->getOption('sync-cache')) {
            $this->syncCachedTaskIds($output);
            return;
        }

        // 检查是否为清理缓存操作
        if ($input->getOption('clear-cache')) {
            self::clearCache($output);
            return;
        }

        // 检查是否为重置进度操作
        if ($input->getOption('reset-progress')) {
            self::resetProgress($output);
            return;
        }

        // 检查是否为查看状态操作
        if ($input->getOption('status')) {
            $this->showStatus($output);
            return;
        }

        // 检查是否为重启指定任务操作
        if ($input->getOption('restart-task')) {
            $taskId = (int)$input->getOption('restart-task');
            $this->restartSpecificTask($taskId, $output);
            return;
        }

        // 检查是否为重启失败任务操作
        if ($input->getOption('restart-failed')) {
            $this->restartFailedTasks($output);
            return;
        }

        // 检查是否为重启指定范围任务操作
        if ($input->getOption('restart-range')) {
            $range = $input->getOption('restart-range');
            $this->restartTaskRange($range, $output);
            return;
        }

        // 检查是否为删除指定ID之前的缓存操作
        if ($input->getOption('clear-before')) {
            $taskId = (int)$input->getOption('clear-before');
            $this->clearTasksBeforeId($taskId, $output);
            return;
        }

        if ($input->getOption('flush-cache')) {
            $this->forceWriteBatchCache($output);
            return;
        }

        $output->writeln('开始处理医案文本数据...');

        try {
            $model = $input->getOption('model');
            $concurrent = (int)$input->getOption('concurrent');

            $this->processMedicalCases($output, $model, $concurrent);
            $output->writeln('医案文本数据处理完成');
        } catch (\Exception $e) {
            $output->writeln('处理医案文本数据时发生错误: ' . $e->getMessage());
            Log::error('医案文本处理器错误: ' . $e->getMessage());
        }
    }

    /**
     * 处理医案数据（单次执行模式，适合外部定时器触发）
     * 
     * @param Output $output 输出对象
     * @param string $model AI模型名称
     * @param int $concurrent 并发数量（此模式下忽略）
     * @return void
     */
    private function processMedicalCases(Output $output, string $model, int $concurrent) {
        $filePath = root_path() . self::MEDICAL_CASE_FILE;
        $outputPath = root_path() . self::OUTPUT_FILE;

        // 检查文件是否存在
        if (!file_exists($filePath)) {
            throw new \Exception('医案文件不存在: ' . $filePath);
        }

        // 初始化任务队列（如果未初始化）
        $this->initTaskQueue($filePath, $output);

        // 获取任务统计
        $totalTasks = Cache::get(self::CACHE_PREFIX . 'total_tasks', 0);
        $output->writeln("总任务数: {$totalTasks}");

        if ($totalTasks == 0) {
            $output->writeln('没有待处理的任务');
            return;
        }

        // 单次执行：处理1条数据
        $this->processSingleTask($output, $model, $outputPath);
    }

    /**
     * 单次处理1条任务（修复版，正确控制任务加载数量）
     * 
     * @param Output $output 输出对象
     * @param string $model AI模型名称
     * @param string $outputPath 输出文件路径
     * @return void
     */
    private function processSingleTask(Output $output, string $model, string $outputPath) {
        // 1. 检查当前正在处理的任务数量
        $processingCount = $this->getProcessingTaskCount();
        if ($processingCount >= self::CONCURRENT_LIMIT) {
            $output->writeln("当前有 {$processingCount} 个任务正在处理中，已达到上限" . self::CONCURRENT_LIMIT . "个，等待下次执行");
            return;
        }

        // 2. 检查处理队列剩余量
        $pendingCount = $this->getPendingTaskCount();
        if ($pendingCount <= 0) {
            $output->writeln('所有任务已处理完成，等待下次执行');
            return;
        }

        $output->writeln("待处理任务数: {$pendingCount}, 正在处理: {$processingCount}");

        // 3. 计算需要加载的任务数量：并发数 - 当前任务数
        $cachedTaskCount = count($this->getCachedTaskIds());
        $needToLoad = self::CONCURRENT_LIMIT - $cachedTaskCount;

        if ($needToLoad > 0 && $pendingCount > 0) {
            $nextTaskId = $this->getNextAvailableTaskId();
            if ($nextTaskId !== null) {
                $this->loadBatchTasksToCache($nextTaskId, $needToLoad);
                $output->writeln("已加载 {$needToLoad} 个任务到缓存，当前缓存任务数: " . count($this->getCachedTaskIds()));
            }
        }

        // 4. 取1条任务执行
        $task = $this->getNextPendingTask();
        if (!$task) {
            $output->writeln('无法获取待处理任务');
            return;
        }

        $output->writeln("开始处理任务: {$task['id']}");

        // 处理任务（所有后续操作都在回调中完成）
        $this->processTaskWithAI($task, $model, $outputPath, $output);

        // 显示当前进度
        $this->showStatus($output);
    }

    /**
     * 获取缓存队列中的任务ID数组
     * 
     * @return array
     */
    private function getCachedTaskIds(): array {
        return Cache::get(self::CACHE_PREFIX . 'cached_task_ids', []);
    }

    /**
     * 设置缓存队列中的任务ID数组
     * 
     * @param array $taskIds 任务ID数组
     * @return void
     */
    private function setCachedTaskIds(array $taskIds): void {
        Cache::set(self::CACHE_PREFIX . 'cached_task_ids', $taskIds, self::CACHE_EXPIRE);
    }

    /**
     * 添加任务ID到缓存队列
     * 
     * @param int $taskId 任务ID
     * @return void
     */
    private function addTaskIdToCache(int $taskId): void {
        $cachedTaskIds = $this->getCachedTaskIds();
        if (!in_array($taskId, $cachedTaskIds)) {
            $cachedTaskIds[] = $taskId;
            $this->setCachedTaskIds($cachedTaskIds);
        }
    }

    /**
     * 从缓存队列中移除任务ID（优化版，确保原子操作）
     * 
     * @param int $taskId 任务ID
     * @return void
     */
    private function removeTaskIdFromCache(int $taskId): void {
        $cachedTaskIds = $this->getCachedTaskIds();
        $key = array_search($taskId, $cachedTaskIds);
        if ($key !== false) {
            unset($cachedTaskIds[$key]);
            $this->setCachedTaskIds(array_values($cachedTaskIds)); // 重新索引数组
        }
    }


    /**
     * 获取下一个可用的任务ID（不自动递增）
     * 
     * @return int|null
     */
    private function getNextAvailableTaskId(): ?int {
        $totalTasks = Cache::get(self::CACHE_PREFIX . 'total_tasks', 0);
        $nextTaskId = Cache::get(self::CACHE_PREFIX . 'next_task_id', 0);

        if ($nextTaskId >= $totalTasks) {
            return null; // 所有任务已处理完成
        }

        return $nextTaskId;
    }

    /**
     * 手动递增下一个任务ID（由外部命令调用）
     * 
     * @return void
     */
    private function incrementNextTaskId(): void {
        $nextTaskId = Cache::get(self::CACHE_PREFIX . 'next_task_id', 0);
        Cache::set(self::CACHE_PREFIX . 'next_task_id', $nextTaskId + 1, self::CACHE_EXPIRE);
    }

    /**
     * 获取待处理任务数量（修复版，基于cached_task_ids统计）
     * 
     * @return int
     */
    private function getPendingTaskCount(): int {
        $totalTasks = Cache::get(self::CACHE_PREFIX . 'total_tasks', 0);
        $nextTaskId = Cache::get(self::CACHE_PREFIX . 'next_task_id', 0);

        // 计算已完成的任务数
        $completedCount = 0;
        $cachedTaskIds = $this->getCachedTaskIds();
        $redis = Cache::store('redis')->handler();

        // 统计已完成的任务
        foreach ($cachedTaskIds as $taskId) {
            $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
            $taskData = $redis->get($taskKey);
            if ($taskData) {
                $task = json_decode($taskData, true);
                if ($task && $task['status'] === 'completed') {
                    $completedCount++;
                }
            } else {
                // 任务数据不存在，可能已被清理，从缓存队列中移除
                $this->removeTaskIdFromCache($taskId);
            }
        }

        return max(0, $totalTasks - $completedCount);
    }

    /**
     * 获取正在处理的任务数量（修复版，基于cached_task_ids统计）
     * 
     * @return int
     */
    private function getProcessingTaskCount(): int {
        $processingCount = 0;
        $cachedTaskIds = $this->getCachedTaskIds();
        $redis = Cache::store('redis')->handler();

        // 统计正在处理的任务
        foreach ($cachedTaskIds as $taskId) {
            $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
            $taskData = $redis->get($taskKey);
            if ($taskData) {
                $task = json_decode($taskData, true);
                if ($task && $task['status'] === 'processing') {
                    $processingCount++;
                }
            } else {
                // 任务数据不存在，可能已被清理，从缓存队列中移除
                $this->removeTaskIdFromCache($taskId);
            }
        }

        return $processingCount;
    }

    /**
     * 获取下一个待处理任务（修复版，基于cached_task_ids查找）
     * 
     * @return array|null
     */
    private function getNextPendingTask(): ?array {
        $totalTasks = Cache::get(self::CACHE_PREFIX . 'total_tasks', 0);
        $nextTaskId = $this->getNextAvailableTaskId();

        if ($nextTaskId === null || $nextTaskId >= $totalTasks) {
            return null;
        }

        // 获取Redis原始对象
        $redis = Cache::store('redis')->handler();
        $cachedTaskIds = $this->getCachedTaskIds();

        // 从缓存队列中查找待处理的任务
        foreach ($cachedTaskIds as $taskId) {
            $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
            $taskData = $redis->get($taskKey);

            if ($taskData) {
                $task = json_decode($taskData, true);
                if ($task && $task['status'] === self::STATUS_PENDING) {
                    // 标记任务为处理中
                    $task['status'] = 'processing';
                    $redis->setex($taskKey, self::CACHE_EXPIRE, json_encode($task, JSON_UNESCAPED_UNICODE));

                    // 递增任务ID
                    $this->incrementNextTaskId();

                    return $task;
                }
            } else {
                // 任务数据不存在，从缓存队列中移除
                $this->removeTaskIdFromCache($taskId);
            }
        }

        // 缓存队列中没有待处理任务，需要加载新任务
        if (!in_array($nextTaskId, $cachedTaskIds)) {
            // 加载新任务到缓存
            $this->loadBatchTasksToCache($nextTaskId, 1);

            // 再次尝试获取任务
            $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $nextTaskId;
            $taskData = $redis->get($taskKey);
            if ($taskData) {
                $task = json_decode($taskData, true);
                if ($task && $task['status'] === self::STATUS_PENDING) {
                    // 标记任务为处理中
                    $task['status'] = 'processing';
                    $redis->setex($taskKey, self::CACHE_EXPIRE, json_encode($task, JSON_UNESCAPED_UNICODE));

                    // 递增任务ID
                    $this->incrementNextTaskId();

                    return $task;
                }
            }
        }

        return null;
    }

    /**
     * 批量加载任务到Redis缓存（优化版，支持指定加载数量）
     * 
     * @param int $startLine 开始行号
     * @param int $batchSize 批量加载数量，默认10
     * @return void
     */
    private function loadBatchTasksToCache(int $startLine, int $batchSize = null): void {
        // 如果没有指定批量大小，使用默认的并发限制
        if ($batchSize === null) {
            $batchSize = self::CONCURRENT_LIMIT;
        }

        $filePath = root_path() . self::MEDICAL_CASE_FILE;
        $handle = fopen($filePath, 'r');
        if (!$handle) {
            return;
        }

        $redis = Cache::store('redis')->handler();
        $loadedCount = 0;

        $lineNumber = 0;
        $validLineCount = 0;

        while (($line = fgets($handle)) !== false && $loadedCount < $batchSize) {
            $line = trim($line);
            if (!empty($line)) {
                $data = json_decode($line, true);
                if (json_last_error() === JSON_ERROR_NONE) {
                    // 检查是否是需要加载的行
                    if ($validLineCount >= $startLine && $validLineCount < $startLine + $batchSize) {
                        $task = [
                            'id' => $validLineCount,
                            'line_number' => $lineNumber,
                            'original_data' => $data,
                            'status' => self::STATUS_PENDING,
                            'created_at' => date('Y-m-d H:i:s'),
                            'processed_at' => null,
                            'result' => null,
                            'error' => null
                        ];

                        // 存储到Redis缓存，设置过期时间
                        $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $validLineCount;
                        $redis->setex($taskKey, self::CACHE_EXPIRE, json_encode($task, JSON_UNESCAPED_UNICODE));

                        // 将任务ID添加到缓存队列
                        $this->addTaskIdToCache($validLineCount);

                        $loadedCount++;
                    }
                    $validLineCount++;
                }
            }
            $lineNumber++;
        }

        fclose($handle);
    }

    /**
     * 清理已处理的任务缓存
     * 
     * @param int $taskId 任务ID
     * @return void
     */
    private function clearTaskCache(int $taskId): void {
        $redis = Cache::store('redis')->handler();
        $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
        $redis->del($taskKey);
        
        // 同时从缓存队列中移除任务ID
        $this->removeTaskIdFromCache($taskId);
    }

    /**
     * 标记任务为已完成
     * 
     * @param int $taskId 任务ID
     * @return void
     */
    private function markTaskAsCompleted(int $taskId): void {
        $redis = Cache::store('redis')->handler();
        $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
        $taskData = $redis->get($taskKey);

        if ($taskData) {
            $task = json_decode($taskData, true);
            if ($task) {
                $task['status'] = 'completed';
                $task['processed_at'] = date('Y-m-d H:i:s');
                $redis->setex($taskKey, self::CACHE_EXPIRE, json_encode($task, JSON_UNESCAPED_UNICODE));
            }
        }
    }

    /**
     * 重置任务状态为待处理
     * 
     * @param int $taskId 任务ID
     * @return void
     */
    private function resetTaskStatus(int $taskId): void {
        $redis = Cache::store('redis')->handler();
        $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
        $taskData = $redis->get($taskKey);

        if ($taskData) {
            $task = json_decode($taskData, true);
            if ($task) {
                $task['status'] = self::STATUS_PENDING;
                $task['processed_at'] = null;
                $task['result'] = null;
                $task['error'] = null;
                $redis->setex($taskKey, self::CACHE_EXPIRE, json_encode($task, JSON_UNESCAPED_UNICODE));
            }
        }
    }

    /**
     * 使用AI处理任务（优化版，增加内容完整性检查）
     * 
     * @param array $task 任务数据
     * @param string $model AI模型名称
     * @param string $outputPath 输出文件路径
     * @param Output $output 输出对象
     * @return void
     */
    private function processTaskWithAI(array $task, string $model, string $outputPath, Output $output): void {
        $originalData = $task['original_data'];
        $content = '病案信息：' . $originalData['messages'][1]['content'];

        // 构建AI请求消息
        $messages = [
            [
                "role" => "system",
                "content" => "你是一个内容调整专员，能对用户输入的信息进行内容调整。"
            ],
            [
                "role" => "user",
                "content" => '/nothink 用户输入的病案信息如下：' . $content
                    . '1. 保留原始医案信息，不得删减关键症状或检查结果；
                2. 对文本进行如下处理：
                            - 去除重复内容；
                - 修正标点符号（如全角逗号、顿号、乱用分号等）；
                - 调整语序，使句子更通顺；
                - 合理断句和换行，增强可读性；
                - 不得添加原文中未出现的信息；
                3. 输出应为一段完整的字符串，不要使用代码块语法（如 ```json 或 ```text）；
                4. 输出格式为纯文本，不包含任何解释性文字或说明；
                5. 输出时请使用 \n 表示换行;'
            ],

        ];

        // 配置AI参数
        $config = [];

        // 使用回调模式进行流式数据处理
        $aiResponse = '';
        $isCompleted = false;
        $hasError = false;
        $errorMessage = '';
        $isResponseValid = false; // 新增：标记响应是否有效
        // 定义回调函数处理流式数据
        $callback = function ($chunk) use (&$aiResponse, &$isCompleted, &$hasError, &$errorMessage, &$isResponseValid, $task, $model, $outputPath, $output, &$originalData) {
            try {
                $sseParser = new SseParser();
                $events = $sseParser->parse($chunk);

                foreach ($events as $event) {
                    // 检查结束标记
                    if ($event['data'] == '[DONE]') {
                        $isCompleted = true;
                        
                        // 检查AI响应是否有效（不为空且长度合理）
                        if (!empty($aiResponse) && strlen($aiResponse) > 10) {
                            $isResponseValid = true;
                            $originalData['messages'][1]['content'] = $aiResponse;
                            // 第一次AI处理完成，使用QWEN2.5进行二次处理
                            $this->processSecondAI($task, $aiResponse, $model, $outputPath, $output, $originalData);
                        } else {
                            // AI响应无效，记录错误
                            $hasError = true;
                            $errorMessage = 'AI响应内容为空或过短，可能处理不完整';
                            $isCompleted = true;
                            
                            // 处理无效响应
                            $this->handleTaskError($task, $errorMessage, $outputPath, $output);
                        }
                        return;
                    }

                    // 处理数据内容
                    if (isset($event['data']) && !empty($event['data'])) {
                        $data = json_decode($event['data'], true);
                        if ($data && isset($data['choices'][0]['delta']['content'])) {
                            $aiResponse .= $data['choices'][0]['delta']['content'];
                        }
                    }
                }
            } catch (\Exception $e) {
                $hasError = true;
                $errorMessage = $e->getMessage();
                $isCompleted = true;

                // 发生错误，在回调中处理错误情况
                $this->handleTaskError($task, $errorMessage, $outputPath, $output);
            }
        };

        // 调用AI服务（流式模式）
        try {
            $this->aiChat($model, $content, $messages, $config, $callback);

            // 等待处理完成（简化等待逻辑）
            $timeout = 400; // 400秒超时
            $startTime = time();
            while (!$isCompleted && (time() - $startTime) < $timeout) {
                usleep(200000); // 等待200ms，减少CPU占用
            }

            // 如果超时，检查是否有有效响应
            if (!$isCompleted) {
                $errorMsg = "任务 {$task['id']} AI处理超时";
                
                // 检查是否有部分有效响应
                if (!empty($aiResponse) && strlen($aiResponse) > 10) {
                    $output->writeln($errorMsg . "，但获得了部分有效响应，将在下次执行时重新处理");
                    Log::warning("医案处理任务超时但有部分响应 - 任务ID: {$task['id']}, 响应长度: " . strlen($aiResponse));
                } else {
                    $output->writeln($errorMsg . "，未获得有效响应，将在下次执行时重新处理");
                    Log::error("医案处理任务超时且无有效响应 - 任务ID: {$task['id']}");
                }

                // 发送超时通知给管理员
                $this->sendAdminNotify($errorMsg, [
                    'task_id' => $task['id'],
                    'error' => 'AI处理超时',
                    'response_length' => strlen($aiResponse),
                    'type' => 'task_timeout'
                ]);
                
                // 重置任务状态，等待下次重新处理
                $this->resetTaskStatus($task['id']);
            }
        } catch (\Exception $e) {
            // AI服务调用失败，记录错误但不更新进度
            $errorMsg = "任务 {$task['id']} AI服务调用失败: " . $e->getMessage() . "，将在下次执行时重新处理";
            $output->writeln($errorMsg);
            Log::error("医案处理AI服务调用失败 - 任务ID: {$task['id']}, 错误: " . $e->getMessage());

            // 发送服务调用失败通知给管理员
            $this->sendAdminNotify($errorMsg, [
                'task_id' => $task['id'],
                'error' => $e->getMessage(),
                'type' => 'ai_service_error'
            ]);
            
            // 重置任务状态，等待下次重新处理
            $this->resetTaskStatus($task['id']);
        }
    }


    /**
     * 发送企业微信日志通知
     * 
     * @param string $message 通知消息
     * @param array $context 上下文信息
     * @return void
     */
    private function sendAdminNotify(string $message, array $context = []): void {
        $webhookUrl = self::WECHAT_WEBHOOK_URL;
        if (empty($webhookUrl)) {
            Log::info("企业微信webhook地址未配置，跳过通知发送: " . $message);
            return;
        }
        try {
            $data = [
                'msgtype' => 'markdown',
                'markdown' => [
                    'content' => "**系统日志通知**\n" .
                        "> 消息：" . $message . "\n" .
                        "> 时间：" . date('Y-m-d H:i:s') . "\n" .
                        (!empty($context) ? "> 上下文：" . json_encode($context, JSON_UNESCAPED_UNICODE) . "\n" : "")
                ]
            ];
            send_post($webhookUrl, $data);
            Log::info("企业微信通知发送成功: " . $message);
        } catch (\Exception $e) {
            Log::error("发送企业微信日志通知失败: " . $e->getMessage());
        }
    }
    /**
     * 使用QWEN2.5进行二次AI处理（优化版，增加内容完整性检查）
     * 
     * @param array $task 任务数据
     * @param string $firstAIResponse 第一次AI响应内容
     * @param string $firstModel 第一次AI模型名称
     * @param string $outputPath 输出文件路径
     * @param Output $output 输出对象
     * @param array $originalData 原始数据
     * @return void
     */
    private function processSecondAI(array $task, string $firstAIResponse, string $firstModel, string $outputPath, Output $output, array $originalData): void {
        $output->writeln("任务 {$task['id']} 第一次AI处理完成，开始二次处理...");



        // 构建二次处理的AI请求消息
        $messages = [
            [
                "role" => "system",
                "content" => "你是一个中医专家，能根据用户给定的信息进行内容生成"
            ],

            [
                "role" => "user",
                "content" => '/nothink 请根据以下病案信息，严格按照中医临床诊疗规范，生成一个专业、严谨的中医辨证论治回复内容块。\n
                        要求如下：
                        1. 回答必须严格基于中医经典理论与权威教材，包括但不限于《伤寒论》《金匮要略》《中医内科学》等；\n
                        2. 输出内容应包含以下模块，按顺序排列：\n
                        - 四诊摘要与辨证分析\n
                        - 明确的证候诊断\n
                        - 病因病机解析\n
                        - 中医疾病诊断\n
                        - 治则治法\n
                        - 推荐中药及配伍意义\n
                        - 经典方剂出处及加减建议\n
                        - 方义解析\n
                        - 煎服方法\n
                        - 中成药推荐（如有）\n
                        - 调护建议\n
                        - 预后判断\n
                        3. 所有内容必须完全基于提供的病案信息，不得添加任何未提及的症状、体征或检查结果；\n
                        4. 不得虚构病情发展、实验室指标、影像学表现等内容；\n
                        5. 推荐的中药和方剂必须出自权威典籍或教材，不得使用非标准方剂或未经证实的偏方；\n
                        6. 表述语言为中文，条理清晰，格式统一，术语准确；\n
                        7. 使用 \\n 表示换行，不使用 Markdown 或其他格式符号；\n
                        8. 请避免使用模板化、空泛、重复性的套话，确保内容具体、实用、符合临床实际。\n
                        \n
                        请以客观、专业的中医临床思维进行分析与撰写。' .
                    "病症信息：
                            " . $originalData['messages'][1]['content'] . "
                            原始诊断：
                            " . $originalData['messages'][2]['content']

            ]
        ];

        // 配置AI参数
        $config = [];

        // 使用回调模式进行二次流式数据处理
        $secondAIResponse = '';
        $isSecondCompleted = false;
        $hasSecondError = false;
        $secondErrorMessage = '';
        $isSecondResponseValid = false; // 新增：标记二次响应是否有效

        // 定义二次处理回调函数
        $secondCallback = function ($chunk) use (&$secondAIResponse, &$isSecondCompleted, &$hasSecondError, &$secondErrorMessage, &$isSecondResponseValid, $task, $firstModel, $outputPath, $output, &$originalData) {
            try {
                $sseParser = new SseParser();
                $events = $sseParser->parse($chunk);

                foreach ($events as $event) {
                    // 检查结束标记
                    if ($event['data'] == '[DONE]') {
                        $isSecondCompleted = true;
                        
                        // 检查二次AI响应是否有效（不为空且长度合理）
                        if (!empty($secondAIResponse) && strlen($secondAIResponse) > 50) {
                            $isSecondResponseValid = true;
                            $originalData['messages'][2]['content'] = $secondAIResponse;
                            // 二次处理完成，调用最终处理
                            $this->handleTaskCompletion($task, $secondAIResponse, $firstModel, $outputPath, $output, $originalData);
                        } else {
                            // 二次AI响应无效，记录错误
                            $hasSecondError = true;
                            $secondErrorMessage = '二次AI响应内容为空或过短，可能处理不完整';
                            
                            // 处理无效响应
                            $errorMsg = "任务 {$task['id']} 二次AI处理失败: " . $secondErrorMessage;
                            $output->writeln($errorMsg);
                            Log::error("医案处理二次AI处理失败 - 任务ID: {$task['id']}, 错误: " . $secondErrorMessage);

                            // 发送错误通知给管理员
                            $this->sendAdminNotify($errorMsg, [
                                'task_id' => $task['id'],
                                'error' => $secondErrorMessage,
                                'response_length' => strlen($secondAIResponse),
                                'type' => 'second_ai_processing_error'
                            ]);

                            // 重置任务状态为待处理，等待下次重新处理
                            $this->resetTaskStatus($task['id']);
                            $output->writeln("任务 {$task['id']} 将在下次执行时重新处理");
                        }
                        return;
                    }

                    // 处理数据内容
                    if (isset($event['data']) && !empty($event['data'])) {
                        $data = json_decode($event['data'], true);
                        if ($data && isset($data['choices'][0]['delta']['content'])) {
                            $secondAIResponse .= $data['choices'][0]['delta']['content'];
                        }
                    }
                }
            } catch (\Exception $e) {
                $hasSecondError = true;
                $secondErrorMessage = $e->getMessage();
                $isSecondCompleted = true;

                // 二次处理发生错误，记录错误并退出，等待外部重新触发
                $errorMsg = "任务 {$task['id']} 二次AI处理失败: " . $e->getMessage() . "，将在下次执行时重新处理";
                $output->writeln($errorMsg);
                Log::error("医案处理二次AI处理失败 - 任务ID: {$task['id']}, 错误: " . $e->getMessage());

                // 发送错误通知给管理员
                $this->sendAdminNotify($errorMsg, [
                    'task_id' => $task['id'],
                    'error' => $e->getMessage(),
                    'type' => 'second_ai_processing_error'
                ]);

                // 重置任务状态为待处理，等待下次重新处理
                $this->resetTaskStatus($task['id']);
                $output->writeln("任务 {$task['id']} 将在下次执行时重新处理");
            }
        };

        // 调用二次AI服务（使用QWEN2.5模型）
        try {
            $this->aiChat('Qwen3-235B-A22B', $firstAIResponse, $messages, $config, $secondCallback);

            // 等待二次处理完成
            $timeout = 400; // 400秒超时
            $startTime = time();
            while (!$isSecondCompleted && (time() - $startTime) < $timeout) {
                usleep(200000); // 等待200ms，减少CPU占用
            }

            // 如果二次处理超时，检查是否有有效响应
            if (!$isSecondCompleted) {
                $errorMsg = "任务 {$task['id']} 二次AI处理超时";
                
                // 检查是否有部分有效响应
                if (!empty($secondAIResponse) && strlen($secondAIResponse) > 50) {
                    $output->writeln($errorMsg . "，但获得了部分有效响应，将在下次执行时重新处理");
                    Log::warning("医案处理二次AI处理超时但有部分响应 - 任务ID: {$task['id']}, 响应长度: " . strlen($secondAIResponse));
                } else {
                    $output->writeln($errorMsg . "，未获得有效响应，将在下次执行时重新处理");
                    Log::error("医案处理二次AI处理超时且无有效响应 - 任务ID: {$task['id']}");
                }

                // 发送超时通知给管理员
                $this->sendAdminNotify($errorMsg, [
                    'task_id' => $task['id'],
                    'error' => '二次AI处理超时',
                    'response_length' => strlen($secondAIResponse),
                    'type' => 'second_ai_timeout'
                ]);

                // 重置任务状态为待处理，等待下次重新处理
                $this->resetTaskStatus($task['id']);
                $output->writeln("任务 {$task['id']} 将在下次执行时重新处理");
            }
        } catch (\Exception $e) {
            // 二次AI服务调用失败，记录错误并退出，等待外部重新触发
            $errorMsg = "任务 {$task['id']} 二次AI服务调用失败: " . $e->getMessage() . "，将在下次执行时重新处理";
            $output->writeln($errorMsg);
            Log::error("医案处理二次AI服务调用失败 - 任务ID: {$task['id']}, 错误: " . $e->getMessage());

            // 发送服务调用失败通知给管理员
            $this->sendAdminNotify($errorMsg, [
                'task_id' => $task['id'],
                'error' => $e->getMessage(),
                'type' => 'second_ai_service_error'
            ]);

            // 重置任务状态为待处理，等待下次重新处理
            $this->resetTaskStatus($task['id']);
            $output->writeln("任务 {$task['id']} 将在下次执行时重新处理");
        }
    }

    /**
     * 处理任务完成（修复版，确保缓存队列同步）
     * 
     * @param array $task 任务数据
     * @param string $aiResponse AI响应内容
     * @param string $model AI模型名称
     * @param string $outputPath 输出文件路径
     * @param Output $output 输出对象
     * @param array $originalData 原始数据
     * @return void
     */
    private function handleTaskCompletion(array $task, string $aiResponse, string $model, string $outputPath, Output $output, array $originalData): void {
        try {
            if (empty($originalData)) {
                throw new \Exception('原始数据为空');
            }

            // 将原始数据转换为一行JSON字符串
            $jsonResult = json_encode($originalData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

            // 根据任务ID确定暂存器
            $batchCacheId = $this->addToBatchCacheByTaskId($jsonResult, $task['id']);
            $output->writeln("任务 {$task['id']} 处理完成，已加入暂存器 {$batchCacheId}");

            // 检查该暂存器是否已满，满则立即写入文件并清空
            $batchCount = $this->getBatchCacheCount($batchCacheId);
            if ($batchCount >= self::CONCURRENT_LIMIT) {
                $this->writeBatchCacheToFile($batchCacheId, $outputPath, $output);
                $output->writeln("暂存器 {$batchCacheId} 已满" . self::CONCURRENT_LIMIT . "条，已写入文件并清空");
            }

            // 标记任务为已完成
            $this->markTaskAsCompleted($task['id']);

            // 清理已处理的任务缓存（包括从缓存队列中移除）
            $this->clearTaskCache($task['id']);
        } catch (\Exception $e) {
            $errorMsg = "任务 {$task['id']} 完成处理时发生错误: " . $e->getMessage();
            $output->writeln($errorMsg);
            Log::error("医案处理任务完成处理失败 - 任务ID: {$task['id']}, 错误: " . $e->getMessage());

            // 发送错误通知给管理员
            $this->sendAdminNotify($errorMsg, [
                'task_id' => $task['id'],
                'error' => $e->getMessage(),
                'type' => 'task_completion_error'
            ]);

            // 重置任务状态为待处理，等待下次重新处理
            $this->resetTaskStatus($task['id']);
            $output->writeln("任务 {$task['id']} 将在下次执行时重新处理");
        }
    }

    /**
     * 根据任务ID计算对应的暂存器ID（动态分配版本）
     * 
     * @param int $taskId 任务ID
     * @return int 暂存器ID
     */
    private function getBatchCacheIdByTaskId(int $taskId): int {
        // 优先查找现有的、未满的暂存器
        $availableBatchCacheId = $this->findAvailableBatchCache();

        if ($availableBatchCacheId !== null) {
            return $availableBatchCacheId;
        }

        // 如果没有可用的暂存器，创建新的暂存器
        return $this->createNewBatchCache();
    }

    /**
     * 查找可用的暂存器（未满的暂存器）
     * 
     * @return int|null 可用的暂存器ID，如果没有则返回null
     */
    private function findAvailableBatchCache(): ?int {
        $redis = Cache::store('redis')->handler();

        // 使用Redis的KEYS命令查找所有活跃的暂存器
        $pattern = 'erp-la:' . self::CACHE_PREFIX . 'batch_cache_*';
        $batchCacheKeys = $redis->keys($pattern);

        foreach ($batchCacheKeys as $key) {
            $batchCacheKey = str_replace('erp-la:', '', $key);
            $batchCache = Cache::get($batchCacheKey, []);
            $count = count($batchCache);

            // 如果暂存器未满，返回其ID
            if ($count < self::CONCURRENT_LIMIT) {
                $batchCacheId = str_replace(self::CACHE_PREFIX . 'batch_cache_', '', $batchCacheKey);
                return (int)$batchCacheId;
            }
        }

        return null; // 没有可用的暂存器
    }

    /**
     * 创建新的暂存器
     * 
     * @return int 新暂存器的ID
     */
    private function createNewBatchCache(): int {
        $redis = Cache::store('redis')->handler();

        // 查找最大的暂存器ID
        $pattern = 'erp-la:' . self::CACHE_PREFIX . 'batch_cache_*';
        $batchCacheKeys = $redis->keys($pattern);

        $maxId = -1;
        foreach ($batchCacheKeys as $key) {
            $batchCacheKey = str_replace('erp-la:', '', $key);
            $batchCacheId = str_replace(self::CACHE_PREFIX . 'batch_cache_', '', $batchCacheKey);
            $maxId = max($maxId, (int)$batchCacheId);
        }

        // 创建新的暂存器ID
        $newBatchCacheId = $maxId + 1;
        $newBatchCacheKey = self::CACHE_PREFIX . 'batch_cache_' . $newBatchCacheId;

        // 初始化新的暂存器
        Cache::set($newBatchCacheKey, [], self::CACHE_EXPIRE);

        return $newBatchCacheId;
    }

    /**
     * 将结果加入指定暂存器（根据任务ID确定）
     * 
     * @param string $result AI处理结果
     * @param int $taskId 任务ID
     * @return int 使用的暂存器ID
     */
    private function addToBatchCacheByTaskId(string $result, int $taskId): int {
        $batchCacheId = $this->getBatchCacheIdByTaskId($taskId);
        $batchCacheKey = self::CACHE_PREFIX . 'batch_cache_' . $batchCacheId;

        // 确保暂存器存在
        if (!Cache::has($batchCacheKey)) {
            Cache::set($batchCacheKey, [], self::CACHE_EXPIRE);
        }

        $batchCache = Cache::get($batchCacheKey, []);
        $batchCache[] = $result;
        Cache::set($batchCacheKey, $batchCache, self::CACHE_EXPIRE);

        return $batchCacheId;
    }

    /**
     * 获取指定暂存器中的数量
     * 
     * @param int $batchCacheId 暂存器ID
     * @return int
     */
    private function getBatchCacheCount(int $batchCacheId): int {
        $batchCacheKey = self::CACHE_PREFIX . 'batch_cache_' . $batchCacheId;
        $batchCache = Cache::get($batchCacheKey, []);
        return count($batchCache);
    }

    /**
     * 将指定暂存器内容写入文件并清空
     * 
     * @param int $batchCacheId 暂存器ID
     * @param string $outputPath 输出文件路径
     * @param Output $output 输出对象
     * @return void
     */
    private function writeBatchCacheToFile(int $batchCacheId, string $outputPath, Output $output): void {
        $batchCacheKey = self::CACHE_PREFIX . 'batch_cache_' . $batchCacheId;
        $batchCache = Cache::get($batchCacheKey, []);

        if (empty($batchCache)) {
            return;
        }

        try {
            // 确保输出目录存在
            $outputDir = dirname($outputPath);
            if (!is_dir($outputDir)) {
                mkdir($outputDir, 0755, true);
            }

            // 写入结果到文件（每行一个JSON）
            $content = '';
            foreach ($batchCache as $result) {
                $content .= $result . "\n";
            }

            // 追加写入文件
            file_put_contents($outputPath, $content, FILE_APPEND | LOCK_EX);

            $output->writeln("已写入 " . count($batchCache) . " 条结果到文件: {$outputPath}");

            // 清空该暂存器
            Cache::delete($batchCacheKey);
        } catch (\Exception $e) {
            $errorMsg = "写入文件失败: " . $e->getMessage();
            $output->writeln($errorMsg);
            Log::error("医案处理写入文件失败: " . $e->getMessage());

            // 发送文件写入失败通知
            $this->sendAdminNotify($errorMsg, [
                'batch_cache_id' => $batchCacheId,
                'output_file' => $outputPath,
                'error' => $e->getMessage(),
                'type' => 'file_write_error'
            ]);
            throw $e;
        }
    }

    /**
     * 处理任务错误（修复版，确保缓存队列同步）
     * 
     * @param array $task 任务数据
     * @param string $errorMessage 错误信息
     * @param string $outputPath 输出文件路径
     * @param Output $output 输出对象
     * @return void
     */
    private function handleTaskError(array $task, string $errorMessage, string $outputPath, Output $output): void {
        $errorMsg = "任务 {$task['id']} 处理失败: " . $errorMessage;
        $output->writeln($errorMsg);
        Log::error("医案处理任务失败 - 任务ID: {$task['id']}, 错误: " . $errorMessage);

        // 发送错误通知给管理员
        $this->sendAdminNotify($errorMsg, [
            'task_id' => $task['id'],
            'error' => $errorMessage,
            'type' => 'task_processing_error'
        ]);

        // 失败时重置任务状态为待处理，下次重新处理
        $this->resetTaskStatus($task['id']);
        $output->writeln("任务 {$task['id']} 将在下次执行时重新处理");
    }

    /**
     * 获取所有暂存器的总数量（优化版）
     * 
     * @return int
     */
    private function getAllBatchCacheCount(): int {
        $totalCount = 0;
        $redis = Cache::store('redis')->handler();

        // 使用Redis的KEYS命令查找所有活跃的暂存器
        $pattern = 'erp-la:' . self::CACHE_PREFIX . 'batch_cache_*';
        $batchCacheKeys = $redis->keys($pattern);

        foreach ($batchCacheKeys as $key) {
            $batchCache = Cache::get(str_replace('erp-la:', '', $key), []);
            $totalCount += count($batchCache);
        }

        return $totalCount;
    }

    /**
     * 显示各暂存器组的详细信息（优化版）
     * 
     * @param Output $output 输出对象
     * @return void
     */
    private function showBatchCacheDetails(Output $output): void {
        $redis = Cache::store('redis')->handler();
        $hasActiveCache = false;

        // 使用Redis的KEYS命令查找所有活跃的暂存器
        $pattern = 'erp-la:' . self::CACHE_PREFIX . 'batch_cache_*';
        $batchCacheKeys = $redis->keys($pattern);

        if (!empty($batchCacheKeys)) {
            $output->writeln("=== 暂存器详情 ===");
            $hasActiveCache = true;

            foreach ($batchCacheKeys as $key) {
                $batchCacheKey = str_replace('erp-la:', '', $key);
                $batchCache = Cache::get($batchCacheKey, []);
                $count = count($batchCache);

                if ($count > 0) {
                    // 从键名中提取暂存器ID
                    $batchCacheId = str_replace(self::CACHE_PREFIX . 'batch_cache_', '', $batchCacheKey);
                    $output->writeln("暂存器 {$batchCacheId}: {$count} 条");
                }
            }
        }

        if (!$hasActiveCache) {
            $output->writeln("暂存器详情: 无活跃暂存器");
        }
    }

    /**
     * 初始化任务队列（优化版，只统计总行数，不创建具体任务）
     * 
     * @param string $filePath 文件路径
     * @param Output $output 输出对象
     * @return void
     */
    private function initTaskQueue(string $filePath, Output $output) {
        // 检查是否已经初始化
        if (Cache::has(self::CACHE_PREFIX . 'initialized')) {
            $output->writeln('任务队列已初始化，跳过初始化步骤');
            return;
        }

        $output->writeln('初始化任务队列...');

        $handle = fopen($filePath, 'r');
        if (!$handle) {
            throw new \Exception('无法打开文件: ' . $filePath);
        }

        $lineNumber = 0;
        $validLineCount = 0;

        while (($line = fgets($handle)) !== false) {
            $line = trim($line);
            if (!empty($line)) {
                // 只验证JSON格式，不创建任务
                $data = json_decode($line, true);
                if (json_last_error() === JSON_ERROR_NONE) {
                    $validLineCount++;
                }
            }
            $lineNumber++;
        }

        fclose($handle);

        // 保存总任务数和初始化状态
        Cache::set(self::CACHE_PREFIX . 'total_tasks', $validLineCount, self::CACHE_EXPIRE);
        Cache::set(self::CACHE_PREFIX . 'next_task_id', 0, self::CACHE_EXPIRE);
        Cache::set(self::CACHE_PREFIX . 'cached_task_ids', [], self::CACHE_EXPIRE);
        Cache::set(self::CACHE_PREFIX . 'initialized', true, self::CACHE_EXPIRE);

        $output->writeln("任务队列初始化完成，总有效行数: {$validLineCount}");
    }

    /**
     * 显示处理状态（修复版，正确显示任务进度）
     * 
     * @param Output $output 输出对象
     * @return void
     */
    private function showStatus(Output $output) {
        $totalTasks = Cache::get(self::CACHE_PREFIX . 'total_tasks', 0);
        $nextTaskId = Cache::get(self::CACHE_PREFIX . 'next_task_id', 0);
        $initialized = Cache::get(self::CACHE_PREFIX . 'initialized', false);
        $cachedTaskIds = $this->getCachedTaskIds();
        $currentBatchCacheId = $this->getCurrentBatchCacheId();
        $batchCount = $this->getAllBatchCacheCount();

        $output->writeln('=== 处理状态 ===');
        $output->writeln("任务队列初始化: " . ($initialized ? '是' : '否'));
        $output->writeln("总任务数: {$totalTasks}");
        $output->writeln("下一个任务ID: {$nextTaskId}");
        $output->writeln("缓存队列任务数: " . count($cachedTaskIds));
        $output->writeln("当前暂存器ID: {$currentBatchCacheId}");
        $output->writeln("暂存器总数: {$batchCount} 条");

        if ($totalTasks > 0) {
            $progress = round(($nextTaskId / $totalTasks) * 100, 2);
            $output->writeln("完成进度: {$progress}%");
            $output->writeln("剩余任务: " . ($totalTasks - $nextTaskId) . " 条");
        }

        // 显示缓存队列详情
        if (!empty($cachedTaskIds)) {
            $output->writeln("缓存队列任务ID: " . implode(', ', $cachedTaskIds));
        }

        // 显示暂存器详情
        $this->showBatchCacheDetails($output);
    }

    /**
     * 清理缓存（完整版，清理所有相关缓存）
     * 
     * @param Output $output 输出对象
     * @return void
     */
    public static function clearCache(Output $output = null): void {
        // 清理必要的缓存键
        $keys = [
            self::CACHE_PREFIX . 'total_tasks',
            self::CACHE_PREFIX . 'next_task_id',
            self::CACHE_PREFIX . 'cached_task_ids',
            self::CACHE_PREFIX . 'initialized',
            self::CACHE_PREFIX . 'current_batch_cache_id'
        ];

        foreach ($keys as $key) {
            Cache::delete($key);
        }

        // 清理可能存在的旧版本task_*缓存和batch_cache_*缓存
        $redis = Cache::store('redis')->handler();

        // 清理任务缓存
        $oldTaskKeys = $redis->keys('erp-la:' . self::CACHE_PREFIX . 'task_*');
        foreach ($oldTaskKeys as $key) {
            $redis->del($key);
        }

        // 清理暂存器缓存
        $oldBatchCacheKeys = $redis->keys('erp-la:' . self::CACHE_PREFIX . 'batch_cache_*');
        foreach ($oldBatchCacheKeys as $key) {
            $redis->del($key);
        }

        if ($output) {
            $output->writeln('缓存已清理（包括任务缓存和暂存器缓存）');
        }
    }

    /**
     * 重置处理进度
     * 
     * @param Output $output 输出对象
     * @return void
     */
    public static function resetProgress(Output $output = null): void {
        Cache::delete(self::CACHE_PREFIX . 'next_task_id');
        Cache::delete(self::CACHE_PREFIX . 'cached_task_ids');
        Cache::delete(self::CACHE_PREFIX . 'initialized');
        Cache::delete(self::CACHE_PREFIX . 'current_batch_cache_id');

        if ($output) {
            $output->writeln('处理进度已重置');
        }
    }

    /**
     * 获取当前可用的暂存器ID
     * 
     * @return int
     */
    private function getCurrentBatchCacheId(): int {
        return Cache::get(self::CACHE_PREFIX . 'current_batch_cache_id', 0);
    }

    /**
     * 重启指定任务ID
     * 
     * @param int $taskId 任务ID
     * @param Output $output 输出对象
     * @return void
     */
    private function restartSpecificTask(int $taskId, Output $output): void {
        $output->writeln("开始重启任务: {$taskId}");

        try {
            // 1. 检查任务队列是否已初始化
            if (!Cache::has(self::CACHE_PREFIX . 'initialized')) {
                $output->writeln('任务队列未初始化，请先运行一次正常处理命令');
                return;
            }

            // 2. 检查任务ID是否有效
            $totalTasks = Cache::get(self::CACHE_PREFIX . 'total_tasks', 0);
            if ($taskId < 0 || $taskId >= $totalTasks) {
                $output->writeln("任务ID无效: {$taskId}，总任务数: {$totalTasks}");
                return;
            }

            // 3. 检查任务是否在缓存中，如果不在则加载
            $cachedTaskIds = $this->getCachedTaskIds();
            if (!in_array($taskId, $cachedTaskIds)) {
                $output->writeln("任务 {$taskId} 不在缓存中，正在加载...");
                $this->loadBatchTasksToCache($taskId, 1);
            }

            // 4. 获取任务数据
            $redis = Cache::store('redis')->handler();
            $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
            $taskData = $redis->get($taskKey);

            if (!$taskData) {
                $output->writeln("任务 {$taskId} 数据不存在，尝试重新加载...");
                $this->loadBatchTasksToCache($taskId, 1);
                $taskData = $redis->get($taskKey);
                
                if (!$taskData) {
                    $output->writeln("任务 {$taskId} 数据加载失败");
                    return;
                }
            }

            $task = json_decode($taskData, true);
            if (!$task) {
                $output->writeln("任务 {$taskId} 数据格式错误");
                return;
            }

            // 5. 检查任务当前状态
            $currentStatus = $task['status'] ?? 'unknown';
            $output->writeln("任务 {$taskId} 当前状态: {$currentStatus}");

            // 6. 重置任务状态
            $this->resetTaskStatus($taskId);
            $output->writeln("任务 {$taskId} 状态已重置为待处理");

            // 7. 确保任务在缓存队列中
            if (!in_array($taskId, $this->getCachedTaskIds())) {
                $this->addTaskIdToCache($taskId);
                $output->writeln("任务 {$taskId} 已添加到缓存队列");
            }

            // 8. 如果任务ID大于等于当前next_task_id，需要调整next_task_id
            $nextTaskId = Cache::get(self::CACHE_PREFIX . 'next_task_id', 0);
            if ($taskId >= $nextTaskId) {
                // 将next_task_id设置为taskId，这样下次处理时会优先处理这个任务
                Cache::set(self::CACHE_PREFIX . 'next_task_id', $taskId, self::CACHE_EXPIRE);
                $output->writeln("已将下一个任务ID调整为: {$taskId}");
            }

            $output->writeln("任务 {$taskId} 重启成功，将在下次执行时重新处理");

            // 9. 显示重启后的状态
            $this->showTaskStatus($taskId, $output);

        } catch (\Exception $e) {
            $errorMsg = "重启任务 {$taskId} 时发生错误: " . $e->getMessage();
            $output->writeln($errorMsg);
            Log::error("重启任务失败 - 任务ID: {$taskId}, 错误: " . $e->getMessage());

            // 发送错误通知给管理员
            $this->sendAdminNotify($errorMsg, [
                'task_id' => $taskId,
                'error' => $e->getMessage(),
                'type' => 'restart_task_error'
            ]);
        }
    }

    /**
     * 重启所有失败的任务
     * 
     * @param Output $output 输出对象
     * @return void
     */
    private function restartFailedTasks(Output $output): void {
        $output->writeln("开始重启所有失败的任务...");

        try {
            // 1. 检查任务队列是否已初始化
            if (!Cache::has(self::CACHE_PREFIX . 'initialized')) {
                $output->writeln('任务队列未初始化，请先运行一次正常处理命令');
                return;
            }

            $totalTasks = Cache::get(self::CACHE_PREFIX . 'total_tasks', 0);
            $restartCount = 0;
            $failedTasks = [];

            // 2. 遍历所有任务，查找失败的任务
            for ($taskId = 0; $taskId < $totalTasks; $taskId++) {
                $redis = Cache::store('redis')->handler();
                $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
                $taskData = $redis->get($taskKey);

                if ($taskData) {
                    $task = json_decode($taskData, true);
                    if ($task) {
                        $status = $task['status'] ?? 'unknown';
                        
                        // 检查是否为失败状态（有错误信息或状态为failed）
                        if ($status === 'failed' || (isset($task['error']) && !empty($task['error']))) {
                            $failedTasks[] = $taskId;
                            $this->restartSpecificTask($taskId, $output);
                            $restartCount++;
                        }
                    }
                } else {
                    // 任务数据不存在，可能是失败后被清理的，重新加载并重启
                    $failedTasks[] = $taskId;
                    $this->restartSpecificTask($taskId, $output);
                    $restartCount++;
                }
            }

            if ($restartCount > 0) {
                $output->writeln("共重启了 {$restartCount} 个失败的任务");
                $output->writeln("失败任务ID: " . implode(', ', $failedTasks));
            } else {
                $output->writeln("没有发现失败的任务");
            }

        } catch (\Exception $e) {
            $errorMsg = "重启失败任务时发生错误: " . $e->getMessage();
            $output->writeln($errorMsg);
            Log::error("重启失败任务错误: " . $e->getMessage());

            // 发送错误通知给管理员
            $this->sendAdminNotify($errorMsg, [
                'error' => $e->getMessage(),
                'type' => 'restart_failed_tasks_error'
            ]);
        }
    }

    /**
     * 重启指定范围的任务（基于缓存）
     * 
     * @param string $range 范围字符串，格式：start-end
     * @param Output $output 输出对象
     * @return void
     */
    private function restartTaskRange(string $range, Output $output): void {
        $output->writeln("开始重启指定范围的任务: {$range}");

        try {
            // 1. 解析范围字符串
            if (!preg_match('/^(\d+)-(\d+)$/', $range, $matches)) {
                $output->writeln("范围格式错误，请使用格式：start-end，例如：0-10");
                return;
            }

            $startTaskId = (int)$matches[1];
            $endTaskId = (int)$matches[2];

            if ($startTaskId > $endTaskId) {
                $output->writeln("起始任务ID不能大于结束任务ID");
                return;
            }

            // 2. 检查任务队列是否已初始化
            if (!Cache::has(self::CACHE_PREFIX . 'initialized')) {
                $output->writeln('任务队列未初始化，请先运行一次正常处理命令');
                return;
            }

            // 3. 获取缓存中实际可用的任务ID
            $availableTaskIds = $this->getAvailableTaskIds();
            $totalAvailableTasks = count($availableTaskIds);
            
            if ($totalAvailableTasks == 0) {
                $output->writeln("缓存中没有可用的任务");
                return;
            }

            $output->writeln("缓存中共有 {$totalAvailableTasks} 个有效任务");
            $output->writeln("可用任务ID: " . implode(', ', $availableTaskIds));

            // 4. 筛选出在指定范围内的任务ID
            $targetTaskIds = [];
            foreach ($availableTaskIds as $taskId) {
                if ($taskId >= $startTaskId && $taskId <= $endTaskId) {
                    $targetTaskIds[] = $taskId;
                }
            }

            if (empty($targetTaskIds)) {
                $output->writeln("在指定范围 {$startTaskId}-{$endTaskId} 内没有找到可用的任务");
                return;
            }

            $count = count($targetTaskIds);
            $output->writeln("找到 {$count} 个任务在指定范围内: " . implode(', ', $targetTaskIds));

            // 5. 显示范围统计信息
            $stats = $this->getTaskRangeStatus($startTaskId, $endTaskId, $output);
            $output->writeln("=== 范围 {$startTaskId}-{$endTaskId} 任务状态统计 ===");
            $output->writeln("总任务数: {$stats['total']}");
            $output->writeln("待处理: {$stats['pending']}");
            $output->writeln("处理中: {$stats['processing']}");
            $output->writeln("已完成: {$stats['completed']}");
            $output->writeln("失败: {$stats['failed']}");
            $output->writeln("未找到: {$stats['not_found']}");

            $restartCount = 0;
            $restartedTasks = [];
            $failedTasks = [];

            // 6. 重启指定范围内的任务
            foreach ($targetTaskIds as $taskId) {
                try {
                    $this->restartSpecificTask($taskId, $output);
                    $restartedTasks[] = $taskId;
                    $restartCount++;
                } catch (\Exception $e) {
                    $failedTasks[] = $taskId;
                    $output->writeln("重启任务 {$taskId} 失败: " . $e->getMessage());
                }
            }

            // 7. 输出重启结果
            $output->writeln("=== 重启结果 ===");
            $output->writeln("成功重启: {$restartCount} 个任务");
            if (!empty($restartedTasks)) {
                $output->writeln("成功重启任务ID: " . implode(', ', $restartedTasks));
            }
            
            if (!empty($failedTasks)) {
                $output->writeln("重启失败任务ID: " . implode(', ', $failedTasks));
            }

            // 8. 显示重启后的状态统计
            $output->writeln("=== 重启后状态统计 ===");
            $this->showTaskRangeStatus($startTaskId, $endTaskId, $output);

        } catch (\Exception $e) {
            $errorMsg = "重启任务范围时发生错误: " . $e->getMessage();
            $output->writeln($errorMsg);
            Log::error("重启任务范围错误: " . $e->getMessage());

            // 发送错误通知给管理员
            $this->sendAdminNotify($errorMsg, [
                'range' => $range,
                'error' => $e->getMessage(),
                'type' => 'restart_task_range_error'
            ]);
        }
    }

    /**
     * 显示指定任务的详细状态
     * 
     * @param int $taskId 任务ID
     * @param Output $output 输出对象
     * @return void
     */
    private function showTaskStatus(int $taskId, Output $output): void {
        $redis = Cache::store('redis')->handler();
        $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
        $taskData = $redis->get($taskKey);

        if (!$taskData) {
            $output->writeln("任务 {$taskId} 数据不存在");
            return;
        }

        $task = json_decode($taskData, true);
        if (!$task) {
            $output->writeln("任务 {$taskId} 数据格式错误");
            return;
        }

        $output->writeln("=== 任务 {$taskId} 状态详情 ===");
        $output->writeln("状态: " . ($task['status'] ?? 'unknown'));
        $output->writeln("创建时间: " . ($task['created_at'] ?? 'unknown'));
        $output->writeln("处理时间: " . ($task['processed_at'] ?? '未处理'));
        
        if (isset($task['error']) && !empty($task['error'])) {
            $output->writeln("错误信息: " . $task['error']);
        }
        
        if (isset($task['result']) && !empty($task['result'])) {
            $output->writeln("处理结果: 已生成");
        }

        // 检查是否在缓存队列中
        $cachedTaskIds = $this->getCachedTaskIds();
        $inCache = in_array($taskId, $cachedTaskIds);
        $output->writeln("在缓存队列中: " . ($inCache ? '是' : '否'));
    }

    /**
     * 显示指定范围内任务的状态统计
     * 
     * @param int $startTaskId 起始任务ID
     * @param int $endTaskId 结束任务ID
     * @param Output $output 输出对象
     * @return void
     */
    private function showTaskRangeStatus(int $startTaskId, int $endTaskId, Output $output): void {
        $stats = $this->getTaskRangeStatus($startTaskId, $endTaskId, $output);
        
        $output->writeln("范围 {$startTaskId}-{$endTaskId} 任务状态:");
        $output->writeln("  总任务数: {$stats['total']}");
        $output->writeln("  待处理: {$stats['pending']}");
        $output->writeln("  处理中: {$stats['processing']}");
        $output->writeln("  已完成: {$stats['completed']}");
        $output->writeln("  失败: {$stats['failed']}");
        $output->writeln("  未找到: {$stats['not_found']}");
    }

    /**
     * 获取指定范围内任务的状态统计
     * 
     * @param int $startTaskId 起始任务ID
     * @param int $endTaskId 结束任务ID
     * @param Output $output 输出对象
     * @return array 状态统计信息
     */
    private function getTaskRangeStatus(int $startTaskId, int $endTaskId, Output $output): array {
        $stats = [
            'total' => 0,
            'pending' => 0,
            'processing' => 0,
            'completed' => 0,
            'failed' => 0,
            'not_found' => 0
        ];

        $redis = Cache::store('redis')->handler();

        for ($taskId = $startTaskId; $taskId <= $endTaskId; $taskId++) {
            $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
            $taskData = $redis->get($taskKey);

            if ($taskData) {
                $task = json_decode($taskData, true);
                if ($task) {
                    $stats['total']++;
                    $status = $task['status'] ?? 'unknown';
                    
                    switch ($status) {
                        case 'pending':
                            $stats['pending']++;
                            break;
                        case 'processing':
                            $stats['processing']++;
                            break;
                        case 'completed':
                            $stats['completed']++;
                            break;
                        case 'failed':
                            $stats['failed']++;
                            break;
                        default:
                            $stats['failed']++; // 未知状态视为失败
                            break;
                    }
                } else {
                    $stats['not_found']++;
                }
            } else {
                $stats['not_found']++;
            }
        }

        return $stats;
    }

    /**
     * 获取当前所有可用的任务ID（基于缓存）
     * 
     * @return array 可用的任务ID数组
     */
    private function getAvailableTaskIds(): array {
        $availableTaskIds = [];
        $redis = Cache::store('redis')->handler();
        
        // 获取缓存队列中的任务ID
        $cachedTaskIds = $this->getCachedTaskIds();
        
        // 检查缓存队列中的任务是否真实存在
        foreach ($cachedTaskIds as $taskId) {
            $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $taskId;
            $taskData = $redis->get($taskKey);
            
            if ($taskData) {
                $task = json_decode($taskData, true);
                if ($task) {
                    $availableTaskIds[] = $taskId;
                }
            }
        }
        
        return $availableTaskIds;
    }

    /**
     * 删除指定ID之前的所有任务缓存（修复版，分别检查缓存和缓存队列）
     * 
     * @param int $taskId 任务ID
     * @param Output $output 输出对象
     * @return void
     */
    private function clearTasksBeforeId(int $taskId, Output $output): void {
        $output->writeln("开始删除任务ID {$taskId} 之前的所有任务缓存...");

        try {
            // 1. 检查任务队列是否已初始化
            if (!Cache::has(self::CACHE_PREFIX . 'initialized')) {
                $output->writeln('任务队列未初始化，请先运行一次正常处理命令');
                return;
            }

            // 2. 检查任务ID是否有效
            $totalTasks = Cache::get(self::CACHE_PREFIX . 'total_tasks', 0);
            if ($taskId < 0 || $taskId >= $totalTasks) {
                $output->writeln("任务ID无效: {$taskId}，总任务数: {$totalTasks}");
                return;
            }

            // 3. 分别获取缓存数据和缓存队列中的任务ID
            $redis = Cache::store('redis')->handler();
            $cachedTaskIds = $this->getCachedTaskIds();
            
            $output->writeln("缓存队列中的任务ID: " . implode(', ', $cachedTaskIds));

            // 4. 检查缓存数据中实际存在的任务
            $existingTaskIds = [];
            foreach ($cachedTaskIds as $cachedTaskId) {
                $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $cachedTaskId;
                $taskData = $redis->get($taskKey);
                if ($taskData) {
                    $task = json_decode($taskData, true);
                    if ($task) {
                        $existingTaskIds[] = $cachedTaskId;
                    }
                }
            }

            $output->writeln("缓存数据中实际存在的任务ID: " . implode(', ', $existingTaskIds));

            // 5. 筛选出需要删除的任务ID（小于指定ID的任务）
            $tasksToDeleteFromCache = [];
            $tasksToDeleteFromQueue = [];

            // 检查缓存数据
            foreach ($existingTaskIds as $existingTaskId) {
                if ($existingTaskId < $taskId) {
                    $tasksToDeleteFromCache[] = $existingTaskId;
                }
            }

            // 检查缓存队列
            foreach ($cachedTaskIds as $cachedTaskId) {
                if ($cachedTaskId < $taskId) {
                    $tasksToDeleteFromQueue[] = $cachedTaskId;
                }
            }

            $output->writeln("需要从缓存数据删除的任务ID: " . implode(', ', $tasksToDeleteFromCache));
            $output->writeln("需要从缓存队列删除的任务ID: " . implode(', ', $tasksToDeleteFromQueue));

            // 6. 删除缓存数据中的任务
            $deletedFromCache = 0;
            foreach ($tasksToDeleteFromCache as $deleteTaskId) {
                $taskKey = 'erp-la:' . self::CACHE_PREFIX . 'task_' . $deleteTaskId;
                $result = $redis->del($taskKey);
                if ($result > 0) {
                    $deletedFromCache++;
                    $output->writeln("已删除缓存数据: 任务ID {$deleteTaskId}");
                }
            }

            // 7. 从缓存队列中删除任务ID
            $deletedFromQueue = 0;
            foreach ($tasksToDeleteFromQueue as $deleteTaskId) {
                $this->removeTaskIdFromCache($deleteTaskId);
                $deletedFromQueue++;
                $output->writeln("已从缓存队列删除: 任务ID {$deleteTaskId}");
            }

            // 8. 统计删除结果
            $output->writeln("=== 删除结果统计 ===");
            $output->writeln("从缓存数据删除: {$deletedFromCache} 个任务");
            $output->writeln("从缓存队列删除: {$deletedFromQueue} 个任务");

            // 9. 调整next_task_id（如果当前next_task_id小于被删除的最大任务ID）
            $maxDeletedTaskId = !empty($tasksToDeleteFromCache) ? max($tasksToDeleteFromCache) : -1;
            $nextTaskId = Cache::get(self::CACHE_PREFIX . 'next_task_id', 0);
            
            if ($maxDeletedTaskId >= 0 && $nextTaskId <= $maxDeletedTaskId) {
                // 找到剩余任务中的最小ID作为新的next_task_id
                $remainingTaskIds = array_diff($cachedTaskIds, $tasksToDeleteFromQueue);
                $minRemainingTaskId = !empty($remainingTaskIds) ? min($remainingTaskIds) : $taskId;
                Cache::set(self::CACHE_PREFIX . 'next_task_id', $minRemainingTaskId, self::CACHE_EXPIRE);
                $output->writeln("已将下一个任务ID调整为: {$minRemainingTaskId}");
            }

            $output->writeln("删除操作完成");

        } catch (\Exception $e) {
            $errorMsg = "删除任务缓存时发生错误: " . $e->getMessage();
            $output->writeln($errorMsg);
            Log::error("删除任务缓存错误: " . $e->getMessage());

            // 发送错误通知给管理员
            $this->sendAdminNotify($errorMsg, [
                'task_id' => $taskId,
                'error' => $e->getMessage(),
                'type' => 'clear_tasks_before_error'
            ]);
        }
    }

    /**
     * 同步cached_task_ids与实际缓存中的任务ID
     * 
     * @param Output $output 输出对象
     * @return void
     */
    private function syncCachedTaskIds(Output $output): void {
        $output->writeln("开始同步cached_task_ids...");
        
        try {
            $redis = Cache::store('redis')->handler();
            
            // 1. 获取当前cached_task_ids
            $currentCachedTaskIds = $this->getCachedTaskIds();
            $output->writeln("当前cached_task_ids: " . implode(', ', $currentCachedTaskIds));
            
            // 2. 获取实际缓存中的任务ID
            $actualTaskIds = [];
            $pattern = 'erp-la:' . self::CACHE_PREFIX . 'task_*';
            $taskKeys = $redis->keys($pattern);
            
            foreach ($taskKeys as $taskKey) {
                $taskData = $redis->get($taskKey);
                if ($taskData) {
                    $task = json_decode($taskData, true);
                    if ($task) {
                        // 从键名中提取任务ID
                        $taskId = str_replace('erp-la:' . self::CACHE_PREFIX . 'task_', '', $taskKey);
                        $actualTaskIds[] = (int)$taskId;
                    }
                }
            }
            
            $output->writeln("实际缓存中的任务ID: " . implode(', ', $actualTaskIds));
            
            // 3. 找出需要删除的ID（在cached_task_ids中但不在实际缓存中）
            $idsToRemove = array_diff($currentCachedTaskIds, $actualTaskIds);
            if (!empty($idsToRemove)) {
                $output->writeln("需要删除的ID: " . implode(', ', $idsToRemove));
                foreach ($idsToRemove as $taskId) {
                    $this->removeTaskIdFromCache($taskId);
                }
            }
            
            // 4. 找出需要添加的ID（在实际缓存中但不在cached_task_ids中）
            $idsToAdd = array_diff($actualTaskIds, $currentCachedTaskIds);
            if (!empty($idsToAdd)) {
                $output->writeln("需要添加的ID: " . implode(', ', $idsToAdd));
                foreach ($idsToAdd as $taskId) {
                    $this->addTaskIdToCache($taskId);
                }
            }
            
            // 5. 获取同步后的结果
            $syncedCachedTaskIds = $this->getCachedTaskIds();
            $output->writeln("同步后的cached_task_ids: " . implode(', ', $syncedCachedTaskIds));
            
            // 6. 统计同步结果
            $removedCount = count($idsToRemove);
            $addedCount = count($idsToAdd);
            
            $output->writeln("=== 同步结果 ===");
            $output->writeln("删除了 {$removedCount} 个无效ID");
            $output->writeln("添加了 {$addedCount} 个缺失ID");
            $output->writeln("当前缓存任务总数: " . count($syncedCachedTaskIds));
            
            if ($removedCount == 0 && $addedCount == 0) {
                $output->writeln("cached_task_ids 已经是同步状态");
            } else {
                $output->writeln("cached_task_ids 同步完成");
            }
            
        } catch (\Exception $e) {
            $errorMsg = "同步cached_task_ids时发生错误: " . $e->getMessage();
            $output->writeln($errorMsg);
            Log::error("同步cached_task_ids错误: " . $e->getMessage());
            
            // 发送错误通知给管理员
            $this->sendAdminNotify($errorMsg, [
                'error' => $e->getMessage(),
                'type' => 'sync_cached_task_ids_error'
            ]);
        }
    }

    /**
     * 强制写入暂存器数据
     * 
     * @param Output $output 输出对象
     * @return void
     */
    private function forceWriteBatchCache(Output $output): void {
        $output->writeln("开始强制写入暂存器数据...");

        try {
            $redis = Cache::store('redis')->handler();
            $pattern = 'erp-la:' . self::CACHE_PREFIX . 'batch_cache_*';
            $batchCacheKeys = $redis->keys($pattern);

            $totalWritten = 0;
            $totalCacheCount = 0;

            foreach ($batchCacheKeys as $key) {
                $batchCacheKey = str_replace('erp-la:', '', $key);
                $batchCache = Cache::get($batchCacheKey, []);
                $cacheCount = count($batchCache);
                $totalCacheCount += $cacheCount;

                if ($cacheCount > 0) {
                    // 从键名中提取batchCacheId（数字部分）
                    if (preg_match('/batch_cache_(\d+)/', $batchCacheKey, $matches)) {
                        $batchCacheId = (int)$matches[1];
                        $outputPath = root_path() . self::OUTPUT_FILE;
                        $this->writeBatchCacheToFile($batchCacheId, $outputPath, $output);
                        $totalWritten += $cacheCount;
                        $output->writeln("已写入暂存器 {$batchCacheId}，包含 {$cacheCount} 条数据");
                    }
                }
            }

            $output->writeln("所有暂存器数据已写入文件，共写入 {$totalWritten} 条数据。");
        } catch (\Exception $e) {
            $output->writeln("强制写入暂存器数据时发生错误: " . $e->getMessage());
        }
    }

    /**
     * 简化的AI聊天方法（用于替代外部GiteeAiService）
     * 
     * @param string $model 模型名称
     * @param string $text 用户输入文本
     * @param array $messages 消息数组
     * @param array $config 配置参数
     * @param callable|null $callback 回调函数
     * @return mixed
     */
    private function aiChat(string $model, string $text, array $messages = [], array $config = [], ?callable $callback = null) {

        // 如果 messages 为空，则构造默认消息体
        if (empty($messages)) {
            $messages = [
                [
                    "role" => "user",
                    "content" => $text
                ]
            ];
        }

        // 构建请求数据
        $data = [
            'model' => $model,
            'stream' => $callback !== null,
            'messages' => $messages,
        ];

        // 添加配置参数
        if (isset($config['maxTokens'])) {
            $data['max_tokens'] = $config['maxTokens'];
        }
        if (isset($config['temperature'])) {
            $data['temperature'] = $config['temperature'];
        }
        if (isset($config['topP'])) {
            $data['top_p'] = $config['topP'];
        }
        if (isset($config['topK'])) {
            $data['top_k'] = $config['topK'];
        }
        if (isset($config['frequencyPenalty'])) {
            $data['frequency_penalty'] = $config['frequencyPenalty'];
        }

        $headers = [
            'Content-Type: application/json',
            'Authorization: Bearer ' . self::AI_API_KEY
        ];

        if ($callback) {
            // 流式请求
            return $this->createStreamChatCompletion($data, $headers, $callback);
        } else {
            // 普通请求
            return $this->createChatCompletion($data, $headers);
        }
    }

    /**
     * 创建普通聊天完成请求
     * 
     * @param array $data 请求数据
     * @param array $headers 请求头
     * @return array
     */
    private function createChatCompletion(array $data, array $headers): array {
        $ch = curl_init(self::AI_BASE_URL);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($response === false || $httpCode !== 200) {
            throw new \Exception('AI服务请求失败: HTTP ' . $httpCode);
        }

        return json_decode($response, true);
    }

    /**
     * 创建流式聊天完成请求
     * 
     * @param array $data 请求数据
     * @param array $headers 请求头
     * @param callable $callback 回调函数
     * @return void
     */
    private function createStreamChatCompletion(array $data, array $headers, callable $callback): void {
        $ch = curl_init(self::AI_BASE_URL);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_TIMEOUT, 400);
        curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use ($callback) {
            $callback($data);
            return strlen($data);
        });

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($response === false || $httpCode !== 200) {
            throw new \Exception('AI流式服务请求失败: HTTP ' . $httpCode);
        }
    }

}
